/*
 * @Author: c
 * @Date: 2024-02-06 10:39:42
 * @LastEditTime: 2024-04-01 02:03:04
 * @LastEditors: c
 * @Description: 
 * @FilePath: \music-web-backend\src\core\music\artist\dao\artist.dao.ts
 * https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
// Copyright 2024 Administrator
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { isNumber } from "class-validator";
import { toLower } from "lodash";
import { MinioClientService } from "src/core/system/minio/minio.service";
import { Brackets, DataSource, Repository, WhereExpressionBuilder } from "typeorm";
import { Album } from "../../album/entities/album.entity";
import { ArtistPageQuery, FavoriteForm } from "../dto";
import { Artist } from "../entities/artist.entity";
import { IArtist } from "../interface/artist.interface";

@Injectable()
export class DArtist implements IArtist {
    constructor(
        @InjectRepository(Artist) private artistRepository: Repository<Artist>,
        private dataSource: DataSource,
        private minioClientService: MinioClientService,
    ) { }

    /**
    * 歌手-歌手所有专辑
    * @param pageDto 
    * @returns 
    */
    getArtistAlbumList(username: string, param: ArtistPageQuery): Promise<[Album[], number]> {
        return
    }

    /**
         * 歌手-新增-我收藏的歌曲
         * @param songForm 
         * @returns 
         */
    async createFavorite(userId: number, { id }: FavoriteForm): Promise<void> {
        //插入favor_user_song表的数据
        await this.artistRepository
            .createQueryBuilder('artist')
            .relation(Artist, 'favoriteUsers')
            .of(id)
            .add(userId)//多对多关系 新增与收藏者的关系
    }


    /**
    * 歌手-删除-我收藏的歌曲
    * @param songForm 
    * @returns 
    */
    async deleteFavorite(userId: number, { id }: FavoriteForm): Promise<void> {
        await this.artistRepository
            .createQueryBuilder('artist')
            .relation(Artist, 'favoriteUsers')
            .of(id)
            .remove(userId)//多对多关系 删除与收藏者的关系
    }

    async myfavorite(userId: number, { pageNum, pageSize }: ArtistPageQuery): Promise<[Artist[], number]> {
        const builder = this.artistRepository.createQueryBuilder('artist')
            .leftJoinAndSelect('artist.pictures', 'picture', `picture.isActive = 1`)
            .leftJoinAndSelect('picture.fileInfo', 'fileInfo')
            .leftJoinAndSelect("song.favoriteUsers", "favor_user")
            .select([
                'artist.id as id',
                'artist.birthday as birthday',
                'artist.weight as weight',
                'artist.blood as blood',
                'artist.name as name',
                'artist.region as region',
                'artist.height as height',
                'artist.status as status',
                'artist.pic as pic',
                'artist.introduce as introduce',
                'artist.create_time as createTime',
                'artist.artist_code as artistCode',
                'artist.birth_place as birthPlace',
                `CASE artist.gender
    WHEN '1' THEN '男'
    WHEN '2' THEN '女'
    WHEN '3' THEN '组合'
    WHEN '4' THEN '乐队'
    ELSE '未知'
    END genderLabel`
            ]).where('artist.deleted = :deleted', { deleted: 0 })

        if (userId) {
            builder.andWhere('favor_user.id = :userId', { userId })
        }

        const total = await builder.getCount()
        const users = await builder.offset((pageNum - 1) * pageSize).limit(pageSize).getRawMany();
        return [users, total]
    }



    async getRecommendSingers(username: string, { pageNum, pageSize }: ArtistPageQuery): Promise<Artist[]> {
        const builder = this.artistRepository.createQueryBuilder('artist')
            .leftJoinAndSelect('artist.pictures', 'picture', `picture.isActive = 1`)
            .leftJoinAndSelect('picture.fileInfo', 'fileInfo')
            .select([
                'artist.id as id',
                'artist.birthday as birthday',
                'artist.weight as weight',
                'artist.blood as blood',
                'artist.name as name',
                'artist.region as region',
                'artist.height as height',
                'artist.status as status',
                'artist.pic as pic',
                'artist.introduce as introduce',
                'artist.create_time as createTime',
                'artist.artist_code as artistCode',
                'artist.birth_place as birthPlace',
                `CASE artist.gender
        WHEN '1' THEN '男'
        WHEN '2' THEN '女'
        WHEN '3' THEN '组合'
        WHEN '4' THEN '乐队'
        ELSE '未知'
        END genderLabel`
            ]).where('artist.deleted = :deleted', { deleted: 0 })

        const total = await builder.getCount()
        const users = await builder.offset((pageNum - 1) * pageSize).limit(pageSize).getRawMany();
        return users
    }




    async page(username: string, { pageNum = 1, pageSize = 10, keywords, name, artistFristLetter, artistRegion, artistGender, status, startTime, endTime }: ArtistPageQuery): Promise<[Artist[], number]> {
        const builder = this.artistRepository.createQueryBuilder('artist')
            .select([
                'artist.id as id',
                'artist.birthday as birthday',
                'artist.weight as weight',
                'artist.blood as blood',
                'artist.name as name',
                'artist.region as region',
                'artist.height as height',
                'artist.status as status',
                'artist.pic as pic',
                'artist.introduce as introduce',
                'artist.create_time as createTime',
                'artist.artist_code as artistCode',
                'artist.birth_place as birthPlace',
                `CASE artist.gender
        WHEN '1' THEN '男'
        WHEN '2' THEN '女'
        WHEN '3' THEN '组合'
        WHEN '4' THEN '乐队'
        ELSE '未知'
        END genderLabel`
            ])
            .where('artist.deleted = :deleted', { deleted: 0 })
            .printSql();

        if (name) {
            builder.andWhere(new Brackets((qb: WhereExpressionBuilder) => {
                qb.where('artist.name like :name', { name: `%${name}%` })
            }))
        }

        if (keywords) {
            //mysql分词查询
            /**create FULLTEXT index artistname_introduce on artist(name,introduce) WITH PARSER ngram;
             * 查看分词长度 SHOW VARIABLES LIKE 'ngram_token_size';
                修改分词长度 在MySQL的配置文件中(.ini)找到[mysqld]字样的地方，在下方添加ngram_token_size=1即可修改为支持1个字符起搜索（范围1~10）
             */
                builder.where('MATCH(name) against(:keywords)', { keywords });
            // where MATCH(title,introduce) against('大飒')
        }

        if (artistFristLetter) {
            builder.andWhere('artist.pinyin_name like :pinyin_name', { pinyin_name: `${toLower(artistFristLetter)}%` })
        }
        if (artistRegion) {
            builder.andWhere('artist.pinyin_name like :artistRegion', { artistRegion: `%${artistRegion}%` })
        }
        if (artistGender) {
            builder.andWhere('artist.gender = :gender', { gender: artistGender })
        }

        if (isNumber(status)) {
            builder.andWhere('artist.status = :status', { status })
        }

        if (startTime) {
            builder.andWhere('artist.create_time >= :startTime', { startTime })
        }
        if (endTime) {
            builder.andWhere('artist.create_time <= :endTime', { endTime })
        }

        const total = await builder.getCount()
        const users = await builder.offset((pageNum - 1) * pageSize).limit(pageSize).getRawMany();
        // const [data, total] = await build.getRawManyAndCount();

        return [users, total]
    }

    async xdpublish(username: string, pageNum: number, pageSize: number): Promise<[Artist[], number]> {
        const build = await this.artistRepository
            .createQueryBuilder("artist")
            .leftJoinAndSelect("artist.artistList", "artist")
            .leftJoinAndSelect("artist.pic", "file_info_pic")
            .leftJoinAndSelect("artist.trackList", "song")
            .leftJoinAndSelect("song.rateFileInfos", "rate_file_info")
            .leftJoinAndSelect('artist.genre', "genre")


            .select([
                'artist.id',
                'artist.title',
                'artist.lang',
                'artist.releaseDate',
                'artist.pushTime',
                'artist.downTime',
                'artist.payModel',
                'artist.createTime',
                'artist.isActive',
                'artist.introduce',
                'artist.id',
                'artist.name',
                'song.id',
                'song.title',
                'song.isVip',
                'song.payModel',
                'song.sort',
                'rate_file_info.size',
                'rate_file_info.rate',
                'rate_file_info.format',
                'rate_file_info.duration',
                'genre.id',
                'genre.categoryName',

                'file_info_pic.id',
                'file_info_pic.percentage',
                'file_info_pic.url',
                'file_info_pic.name',
                'file_info_pic.mimeType',
                'file_info_pic.uid',
                'file_info_pic.lastModified',
            ])
            .orderBy("artist.createTime", 'ASC')
            .offset((pageNum - 1) * pageSize)
            .limit(pageSize)

        if (username) {
            build.leftJoinAndSelect("artist.favoriteUsers", "favor_user", "favor_user.username = :useranme")
            build.addSelect([
                'favor_user.id',
                'favor_user.username'
            ])
            build.setParameter('useranme', username)
        }

        const [data, total] = await build.getManyAndCount();

        return [data, total]
    }
}